package gang.org.springframework.framework.factory;

import gang.org.springframework.framework.bean.GangBeanDefinition;
import gang.org.springframework.framework.bean.GangBeanDefinitionHolder;
import gang.org.springframework.framework.bean.GangRootBeanDefinition;
import gang.org.springframework.framework.bean.GangTypeConverter;
import gang.org.springframework.framework.beans.factory.GangObjectProvider;
import gang.org.springframework.framework.factory.config.GangDependencyDescriptor;
import gang.org.springframework.framework.support.*;
import gang.org.springframework.framework.util.GangBeanFactoryUtils;
import gang.org.springframework.framework.util.GangCollectionUtils;
import gang.org.springframework.framework.util.GangObjectUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author gang.chen
 * @since 2021/6/14 13:56
 */
public class GangDefaultListableBeanFactory extends GangAbstractAutowireCapableBeanFactory implements GangConfigurableListableBeanFactory,GangBeanDefinitionRegistry {

    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

    private final Map<String,GangBeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    public GangAutowireCandidateResolver autowireCandidateResolver = GangSimpleAutowireCandidateResolver.insance;

    public final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);


    /**
     * 业务意义
     * 0 = "gang.org.springframework.framework.annotation.internalConfigurationAnnotationProcessor"
     * 1 = "gang.org.springframework.framework.annotation.internalAutowiredAnnotationProcessor"
     * 2 = "springbootManualApplication"
     * 3 = "gang.org.springframework.framework.web.servlet.GangDispatcherServletAutoConfiguration"
     * 4 = "gang.org.springframework.framework.web.tomcat.GangServletWebServerFactoryAutoConfiguration"
     * 5 = "gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration$GangEnableWebMvcConfiguration"
     * 6 = "mvcResourceUrlProvider"
     * 7 = "gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration"
     *
     * 解析完spring.factories后，一共创建了8个BeanDefinition
     * */
    @Override
    public void registerBeanDefinition(String beanName, GangBeanDefinition beanDefinition) {
        GangBeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if(null == existingDefinition)
        {
            this.beanDefinitionNames.add(beanName);
            this.beanDefinitionMap.put(beanName,beanDefinition);
        }
    }

    //TODO
    @Override
    public String[] getBeanDefinitionNames() {
        return beanDefinitionNames.stream().toArray(String[]::new);
    }

    @Override
    public String[] getBeanNamesForType(Class<?> type) {
        return getBeanNamesForType(type, true, true);
    }

    /**
     * 业务意义
     * 1）给定指定的接口类 E.g GangApplicationListener.class，返回接口实现类的Bean名称
     * */
    @Override
    public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) {

        //if(!isConfigurationFrozen()|| type ==null || !allowEagerInit)
        return doGetBeanNamesForType(GangResolvableType.forRawClass(type),includeNonSingletons,true);
    }

    /**
     * @param type GangResolvableType 是对class类的封装
     * @param allowEagerInit default value is true
     * 业务意义
     * 1，GangResolvableType是对类封装 E.g GangApplicationListener.class
     * 2, 输入指定接口/class类 E.g GangApplicationListener.class，返回接口的实现类Bean名称集合
     * 3，beanDefinitionNames List 集合值列表
     * # = "gang.org.springframework.framework.annotation.internalConfigurationAnnotationProcessor"
     * # = "gang.org.springframework.framework.annotation.internalAutowiredAnnotationProcessor"
     * # = "springbootManualApplication"
     * # = "gang.org.springframework.framework.web.servlet.GangDispatcherServletAutoConfiguration"
     * # = "gang.org.springframework.framework.web.tomcat.GangServletWebServerFactoryAutoConfiguration"
     * # = "gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration$GangEnableWebMvcConfiguration"
     * # = "mvcResourceUrlProvider"
     * # = "gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration"
     * */
    public String[] doGetBeanNamesForType(GangResolvableType type, boolean includeNonSingletons,boolean allowEagerInit){

        List<String> result = new ArrayList<>();
        for (String beanDefinitionName : this.beanDefinitionNames) {

            /*
             * 问题 beanDefinitionName = requestMappingHandlerMapping时， mbd.getTargetType() = null?
             * */
            GangRootBeanDefinition mbd = getMergedLocalBeanDefinition(beanDefinitionName);

            /*
             * 业务意义
             * mbd在方法isFactoryBean中，以下属性被赋值，判断BeanDefinition是否为一个FactoryBean
             * 1）resolvedTargetType 赋值
             * 2）isFactoryBean 赋值
             * 3）factoryMethodReturnType 赋值
             * 4）factoryMethodToIntrospect 赋值
             * 5）predictBeanType()方法首次被调用
             * */
            boolean isFactoryBean = isFactoryBean(beanDefinitionName, mbd);

            //TODO
            boolean matchFound = false;

            if (!isFactoryBean) {
                if (includeNonSingletons || isSingleton(beanDefinitionName,null,null)) {
                    /**
                     *业务意义
                     * 判定beanDefinitionName是否为 type的实现类
                     * @param beanDefinitionName 值 “mvcResourceUrlProvider”
                     * @param type 被封装的java对象 例如：“GangApplicationListener.class”
                     *
                     * */
                    matchFound = isTypeMatch(beanDefinitionName,type,false);
                }
            }else {
                //TODO 暂时不编码
            }

            //TODO
            if(matchFound){
                result.add(beanDefinitionName);
            }
        }
        return result.stream().toArray(String[]::new);
    }

    /**
     * 业务意义
     * 1）beanDefinitionMap 第一次初始化是在什么时间
     * */
    @Override
    public GangBeanDefinition getBeanDefinition(String beanName)
    {
        return this.beanDefinitionMap.get(beanName);
    }

    @Override
    public void preInstantiatedSingletons() {

        /**
         * 问题
         * 1）当前有多少个bean definitions？
         * @springbootManualApplication
         * @mvcResourceUrlProvider
         * @gang.org.springframework.framework.annotation.internalConfigurationAnnotationProcessor
         * @gang.org.springframework.framework.annotation.internalAutowiredAnnotationProcessor
         * @gang.org.springframework.framework.web.servlet.GangDispatcherServletAutoConfiguration
         * @gang.org.springframework.framework.web.tomcat.GangServletWebServerFactoryAutoConfiguration
         * @gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration$GangEnableWebMvcConfiguration
         * @gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration
         * 共8个
         * 2）都是从哪里初始化而来？
         * */
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

        //业务一：触发所有非懒加载的bean完成初始化
        for (String beanName : beanNames) {
            //从缓存中获取BeanDefinition，以beanName为条件
            GangRootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

            //业务上验证该BeanDefinition为一个单例，非抽象，非懒加载
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

                if (isFactoryBean(beanName)) {
                    //TODO
                }else {
                    getBean(beanName);
                }
            }
        }

        //业务二：触发post-initialization初始化回调 TODO
    }



    @Override
    public boolean containsBeanDefinition(String beanName) {
        return this.beanDefinitionMap.containsKey(beanName);
    }


    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        super.registerSingleton(beanName,singletonObject);
    }

    /**
     * 业务意义?
     * TODO
     * */
    private boolean isSingleton(String beanName, GangRootBeanDefinition mbd, GangBeanDefinitionHolder dbd){
        return true;
    }


    /**
     * @param descriptor 描述器是对GangMethodParameter对象的封装
     * */
    @Override
    public Object resolveDependency(GangDependencyDescriptor descriptor, String requestingBeanName, Set<String> autowiredBeanNames, GangTypeConverter typeConverter) {

        if (false){
            //TODO
        }
        else if (GangObjectFactory.class == descriptor.getDependencyType() || GangObjectProvider.class == descriptor.getDependencyType()){
            /**
             * 业务意义
             * 处理配置bean：tomcatServletWebServerFactory
             * */
            return new GangDependencyObjectProvider(descriptor, requestingBeanName);
        }
        else if (false){
            //TODO
        }
        else {
            Object result = null;
            if (result == null) {
                result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
            }
            return result;
        }

        return null;
    }

    public Object doResolveDependency(GangDependencyDescriptor descriptor,
                                      String beanName,
                                      Set<String> autowiredBeanNames,
                                      GangTypeConverter typeConverter){
        //ThreadLocal 存储 InjectionPoint

        try {
            Object shortcut = null;

            if (shortcut != null) {
                return shortcut;
            }
            Class<?> type = descriptor.getDependencyType(); //获取构造方法中的参数对象 #ResourceProperties
            Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
            if (value != null) {
                //TODO
            }
            Object multipleBean = null;
            if (multipleBean != null) {
                //TODO
                return multipleBean;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); // 完成构造方法中，指定对象的实例化
            if (matchingBeans.isEmpty()) {
                //TODO
                return null;
            }
            String autowiredBeanName = "";
            Object instanceCandidate = null;

            if (matchingBeans.size() > 1) {
                //TODO
            }else {
                Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
                autowiredBeanName = entry.getKey();
                instanceCandidate = entry.getValue();
            }

            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(autowiredBeanName);
            }

            if (false){
                //TODO
            }

            Object result = instanceCandidate;

            if (false){
                //TODO
            }
            if (false){
                //TODO
            }
            return result;

        }finally {
            //TODO
        }
    }

    public GangAutowireCandidateResolver getAutowireCandidateResolver() {
        return autowireCandidateResolver;
    }


    public Map<String, Object> findAutowireCandidates(String beanName, Class<?> requiredType, GangDependencyDescriptor descriptor){

        //String candidateNames[] = candidateNames = GangBeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, true);//获取Spring Bean 的名称

        String candidateNames[];
        if (descriptor.methodParameter.getNestedParameterType() == Object.class) {
            candidateNames = new String[]{descriptor.methodParameter.getExecutable().getParameters()[descriptor.parameterIndex].getName()};
        }else {
            candidateNames = GangBeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, true);//获取Spring Bean 的名称
        }

        Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
        for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) { //对BeanFactory特殊处理
            Class<?> autowiringType = classObjectEntry.getKey(); //BeanFactory.class
            if (autowiringType.isAssignableFrom(requiredType)) { //BeanFactory 是 GangDefaultListableBeanFactory的实现类
                Object autowiringValue = classObjectEntry.getValue(); //GangDefaultListableBeanFactory实例
                autowiringValue = GangAutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
                if (requiredType.isInstance(autowiringValue)) {
                    result.put(GangObjectUtils.identityToString(autowiringValue), autowiringValue);
                    break;
                }
            }
        }

        for (String candidate : candidateNames) {
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }

        if (result.isEmpty()) {
            //TODO
        }

        return result;
    }

    public boolean isSelfReference(String beanName, String candidateName){
        return false;
    }

    public boolean isAutowireCandidate(String beanName, GangDependencyDescriptor descriptor){
        return true;
    }

    public void addCandidateEntry(Map<String, Object> candidates,
                                  String candidateName,
                                  GangDependencyDescriptor descriptor,
                                  Class<?> requiredType){
        if (false){
            //TODO
        }
        else if(true){
            /*
             *
             * 1）private final Object resourceProperties;
             * 2）private final Object mvcProperties;
             * 3）private final Object webProperties;
             * 4）private final GangListableBeanFactory beanFactory;
             * 5）private final Object mvcRegistrations;
             * 6）GangListableBeanFactory beanFactory
             * 业务处理场景一
             * 1，2，3，4，5 前5个参数直接创建Object返回即可 TODO
             * 业务处理场景二
             * 6 通过BeanFactory工厂对象来返回
             * */
            Class<?> dependencyType = descriptor.getDependencyType();

            Object beanInstance;

            if(dependencyType != Object.class){
                beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);//通过工厂BeanFactory创建 spring bean
            }else {
                //TODO
                beanInstance = new Object();
            }

            candidates.put(candidateName, beanInstance);
        }
        else {
            //TODO
        }
    }

    @Override
    public void registerResolvaleDependency(Class<?> dependencyType, Object autowiredValue) {

        //IF TODO

        this.resolvableDependencies.put(dependencyType, autowiredValue);
    }

    public interface GangBeanObjectProvider<T> extends GangObjectProvider<T>, Serializable{}


    public class GangDependencyObjectProvider implements GangBeanObjectProvider<Object>{

        public final GangDependencyDescriptor descriptor;

        public final boolean optional;

        public final String beanName;

        public GangDependencyObjectProvider(GangDependencyDescriptor descriptor, String beanName)
        {
            this.descriptor = new GangNestedDependencyDescriptor(descriptor);

            //TODO
            this.optional = false;

            this.beanName = beanName;
        }

        @Override
        public Object getObject() {
            return null;
        }
    }

    public static class GangNestedDependencyDescriptor extends GangDependencyDescriptor
    {
        public GangNestedDependencyDescriptor(GangDependencyDescriptor original)
        {
            super(original);

            //TODO
        }
    }



    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) {

        String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);

        Map<String, T> result = GangCollectionUtils.newLinkedHashMap(beanNames.length);

        for (String beanName : beanNames) {

            try{
                Object beanInstance = getBean(beanName);

                if (!(beanInstance instanceof GangNullBean)) {

                    result.put(beanName, (T) beanInstance);
                }

            }catch (Exception e){
                //TODO
            }
        }
        return result;
    }
}
